;; -*- lexical-binding: t -*-

;;; Some Functions.

;; Load the mode written by me.
(add-to-list 'load-path "~/.emacs.d/local-mode")
(require 'SHELX-mode)
(autoload 'astyle "astyle-utils" nil t)
(eval-when-compile
  (require 'SHELX-mode))
;; (require 'emoji)
;; (require 'bc-mode)
;; (require 'hexo-utils)

(defadvice kill-ring-save (before slick-copy activate compile)
  "When called interactively with no active region, copy a single line instead."
  (interactive (if mark-active (list (region-beginning) (region-end))
                 (message "Copied line")
                 (list (line-beginning-position)
                       (line-beginning-position 2)))))

(defadvice kill-region (before slick-cut (beg end &optional yank-handler) activate compile)
  "When called interactively with no active region, kill a single line instead."
  (interactive (if mark-active (list (region-beginning) (region-end))
                 (message "Cut line")
                 (list (line-beginning-position)
                       (line-beginning-position 2)))))

(defun make-a-long-sentence (start end)
  "Make a long sentence and also works on region."
  (interactive (if (use-region-p) (list (region-beginning) (region-end))
		 (list (line-beginning-position)
		       (if (<= (line-end-position 2) (point-max))
			   (line-end-position 2)
			 (line-end-position)))))
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (delete-trailing-whitespace (point-min) (point-max))
      (goto-char (point-min))
      (while (< (point) (point-max))
	(end-of-line)
	(cond
	 ((and (= (point) (point-max))))
	 ((and (char-before) (char-equal (char-before) ?-))
	  (delete-char -1)
	  (delete-indentation -1)
	  (delete-horizontal-space))
	 ((and (char-before) (string-match "\\cc" (char-to-string (char-before))))
	  (delete-indentation -1)
	  (delete-horizontal-space))
	 (t (delete-indentation -1))))
      (when current-prefix-arg
	(dolist (pairs
		 '(("\\([,.]\\)\\([^[:blank:],.]\\)" . "\\1 \\2")
		   ("\\(\\.\\)[[:blank:]]+\\(,\\)" . "\\1\\2")
		   ("\\[[:blank:]]+\\([.,]\\)" . "\\1")
		   ))
	  (goto-char (point-min))
	  (while (re-search-forward (car pairs) nil t)
	    (replace-match (cdr pairs) nil nil))))))
  (message "make-a-long-sentence completely."))

(global-set-key (kbd "H-j") #'make-a-long-sentence)

(unless (version< emacs-version "26.0")
  (connection-local-set-profile-variables
   'remote-bash
   '((explicit-shell-file-name . "/bin/bash")
     (explicit-bash-args . ("-i"))))

  (connection-local-set-profile-variables
   'remote-busybox
   '((explicit-shell-file-name . "/bin/sh")
     (busybox . t)))

  (connection-local-set-profile-variables
   'remote-bash-sdf
   '((explicit-shell-file-name . "/usr/pkg/bin/bash")
     (explicit-bash-args . ("-himBH"))))

  ;; (connection-local-set-profile-variables
  ;;  'remote-bash-android
  ;;  '((explicit-shell-file-name . "/data/data/com.termux/files/usr/bin/bash")
  ;;    (explicit-bash-args . ("-himBH"))
  ;;    (tramp-methods . (("sshx"
  ;; 		       (tramp-login-program "ssh")
  ;; 		       (tramp-login-args
  ;; 			(("-l" "%u")
  ;; 			 ("-p" "%p")
  ;; 			 ("%c")
  ;; 			 ("-e" "none")
  ;; 			 ("-t" "-t")
  ;; 			 ("%h")
  ;; 			 ("/data/data/com.termux/files/usr/bin/bash")))
  ;; 		       (tramp-async-args
  ;; 			(("-q")))
  ;; 		       (tramp-remote-shell "/data/data/com.termux/files/usr/bin/bash")
  ;; 		       (tramp-remote-shell-login
  ;; 			("-l"))
  ;; 		       (tramp-remote-shell-args
  ;; 			("-c")))
  ;; 		      ("scpx"
  ;; 		       (tramp-login-program "ssh")
  ;; 		       (tramp-login-args
  ;; 			(("-l" "%u")
  ;; 			 ("-p" "%p")
  ;; 			 ("%c")
  ;; 			 ("-e" "none")
  ;; 			 ("-t" "-t")
  ;; 			 ("%h")
  ;; 			 ("/data/data/com.termux/files/usr/bin/bash")))
  ;; 		       (tramp-async-args
  ;; 			(("-q")))
  ;; 		       (tramp-remote-shell "/data/data/com.termux/files/usr/bin/bash")
  ;; 		       (tramp-remote-shell-login
  ;; 			("-l"))
  ;; 		       (tramp-remote-shell-args
  ;; 			("-c"))
  ;; 		       (tramp-copy-program "scp")
  ;; 		       (tramp-copy-args
  ;; 			(("-P" "%p")
  ;; 			 ("-p" "%k")
  ;; 			 ("-q")
  ;; 			 ("-r")
  ;; 			 ("%c")))
  ;; 		       (tramp-copy-keep-date t)
  ;; 		       (tramp-copy-recursive t)))))

  ;; (add-to-list
  ;;  'tramp-methods
  ;;  '("termux"
  ;;    (tramp-login-program "ssh")
  ;;    (tramp-login-args
  ;;     (("-l" "%u")
  ;;      ("-p" "%p")
  ;;      ("%c")
  ;;      ("-e" "none")
  ;;      ("-t" "-t")
  ;;      ("%h")
  ;;      ("/data/data/com.termux/files/usr/bin/bash")))
  ;;    (tramp-async-args
  ;;     (("-q")))
  ;;    (tramp-remote-shell "/data/data/com.termux/files/usr/bin/bash")
  ;;    (tramp-remote-shell-login
  ;;     ("-l"))
  ;;    (tramp-remote-shell-args
  ;;     ("-c"))))

  ;; (add-to-list 'tramp-remote-path
  ;; 	     "/data/data/com.termux/files/usr/bin/")

  ;; (add-to-list 'tramp-remote-path
  ;; 	     "/data/data/com.termux/files/usr/bin/applets/")

  (dolist (p '("sshx" "scpx"))
    (connection-local-set-profiles
     `(:application tramp :protocol ,p :machine "sdf")
     'remote-bash-sdf))

  (dolist (m '("bandwagon" "kvm" "E5internet" "E5wlan" "E5" "E5tunnel"))
    (dolist (p '("sshx" "scpx"))
      (connection-local-set-profiles
       `(:application tramp :protocol ,p :machine ,m)
       'remote-bash)))

  (dolist (p '("sshx" "scpx"))
    (connection-local-set-profiles
     `(:application tramp :protocol ,p :machine "pandorabox")
     'remote-busybox))

  ;; (dolist (p '("sshx" "scpx"))
  ;;   (connection-local-set-profiles
  ;;    `(:application tramp :protocol ,p :machine "Android")
  ;;    'remote-bash-android)))
  )

(defmacro make--shell (name &rest arglist)
  `(defun ,(intern (format "%S-shell" name)) ,arglist
     (interactive)
     (let ((default-directory ,(format "/scpx:%S:" name)))
       (shell (generate-new-buffer-name ,(format "*%S*" name))))))

(make--shell bandwagon)
(make--shell E5internet)
(make--shell E5wlan)
(make--shell E5)
(make--shell E5tunnel)
(make--shell pandorabox)
(make--shell kvm)

(make--shell sdf)
;; (make--shell Android)

(defun Android-shell ()
  "All the dirty hacks for Trumx on Android."
  (interactive)
  (dolist (p '("sshx" "scpx"))
    (setf (car (last (cadr (assq 'tramp-login-args (cdr (assoc p tramp-methods))))))
          '("sh")))
  (add-to-list 'tramp-connection-properties
               (list (regexp-quote "Android") "remote-shell" "sh"))
  (add-to-list 'tramp-remote-path 'tramp-own-remote-path)
  (add-to-list 'tramp-remote-path "/system/bin")
  (add-to-list 'tramp-remote-path "/data/data/com.termux/files/usr/bin/")
  (add-to-list 'tramp-remote-process-environment "TMPDIR=$HOME")
  (let ((default-directory "/scpx:Android:")
	(explicit-shell-file-name "/data/data/com.termux/files/usr/bin/bash"))
    (shell (generate-new-buffer-name "*Android*"))))

(defun run-calc (expr &optional replace)
  "Calculate the `expr' using GNU bc.
If called interactively, the user is asked for input.  If called on
region the selected expression is used as input.  By default display
output in temp buffer `*BC Output*'.  With prefix, insert the output."
  (interactive
   (list (if (use-region-p)
	     (buffer-substring-no-properties
	      (region-beginning)
	      (region-end))
	   (quick-calc current-prefix-arg))
	 current-prefix-arg))
  (require 'calc)
  (let ((output (calc-eval expr)))
    (if (and replace output)
	(when (use-region-p)
	  (delete-region (region-beginning) (region-end))
	  (insert output))
      (message "Result: %s" output))))

(global-set-key (kbd "H-e") #'run-calc)

(defun bwg ()
  (interactive)
  (if (string-equal system-type "windows-nt")
      (progn
	(unless (process-status "ShadowSocks-local")
	  (set-process-coding-system
	   (start-process
	    "ShadowSocks-local"
	    "*ShadowSocks Local*"
	    "C:/msys64/mingw64/bin/ss-local.exe"
	    "-u" "-c" "C:/msys64/etc/shadowsocks/bandwagon.json")
	   'undecided-dos))
	
	(unless (process-status "ShadowSocks-kcptun")
	  (set-process-coding-system
	   (start-process
	    "ShadowSocks-kcptun"
	    "*ShadowSocks Kcptun*"
	    "c:/msys64/mingw64/opt/bin/client_windows_amd64.exe"
	    "-c" "C:/msys64/etc/kcptun.json")
	   'undecided-dos))
	
	(unless (process-status "ShadowSocks-tunnel")
	  (mapc (lambda (address)
		  (set-process-coding-system
		   (start-process
		    "ShadowSocks-tunnel"
		    "*ShadowSocks Tunnel*"
		    "C:/msys64/mingw64/bin/ss-tunnel.exe"
		    "-u" "-c" "C:/msys64/etc/shadowsocks/bandwagon.json"
		    "-L" address "-l" (cadr (split-string address ":")))
		   'undecided-dos)
		  )
		'("8.8.8.8:53"
		  "74.125.28.108:993"
		  "74.125.135.108:587"))))

    (start-process "ShadowSocks" "*ShadowSocks Server*" "sudo" "systemctl" "start" "shadowsocks-libev@bandwagon")))

(defun vultr ()
  (interactive)
  (let ((ip (read-string "IP: ")))
    (when (string-equal system-type "windows-nt")
      (unless (process-status "ShadowSocks-local")
	(set-process-coding-system
	 (start-process
	  "ShadowSocks-local"
	  "*ShadowSocks Local*"
	  "C:/msys64/mingw64/bin/ss-local.exe"
	  "-u" "-c" "C:/msys64/etc/shadowsocks/config.json"
	  "-s" ip)
	 'undecided-dos))
      
      (unless (process-status "ShadowSocks-tunnel")
	(set-process-coding-system
	 (start-process
	  "ShadowSocks-tunnel"
	  "*ShadowSocks Tunnel*"
	  "C:/msys64/mingw64/bin/ss-tunnel.exe"
	  "-u" "-c" "C:/msys64/etc/shadowsocks/config.json"
	  "-s" ip
	  "-L" "8.8.8.8:53" "-l" "53")
	 'undecided-dos)))))

(defun kvm ()
  (interactive)
  (if (string-equal system-type "windows-nt")
      (progn
      	(unless (process-status "ShadowSocks-local")
      	  (set-process-coding-system
      	   (start-process
      	    "ShadowSocks-local"
      	    "*ShadowSocks Local*"
      	    "C:/msys64/mingw64/bin/ss-local.exe"
      	    "-u" "-c" "C:/msys64/etc/shadowsocks/kvm.json")
      	   'undecided-dos))

      	(unless (process-status "ShadowSocks-tunnel")
      	  (mapc (lambda (address)
      		  (set-process-coding-system
      		   (start-process
      		    "ShadowSocks-tunnel"
      		    "*ShadowSocks Tunnel*"
      		    "C:/msys64/mingw64/bin/ss-tunnel.exe"
      		    "-u" "-c" "C:/msys64/etc/shadowsocks/kvm.json"
      		    "-L" address "-l" (cadr (split-string address ":")))
      		   'undecided-dos)
      		  )
      		'("8.8.8.8:53"
      		  "74.125.23.108:993"
      		  "74.125.203.109:587"))))
    ;;   (progn
    ;; 	(unless (process-status "ShadowSocks-local")
    ;;   	   (start-process
    ;;   	    "ShadowSocks"
    ;;   	    "*ShadowSocks*"
    ;;   	    "C:/msys64/mingw64/opt/bin/shadowsocks2-win64.exe"
    ;;   	    "-c" "'ss://XCHACHA20:your-password@[server_address]:8488'"

    ;; 	    shadowsocks2   \
    ;; -verbose -socks :1080 -u -udptun :8053=8.8.8.8:53,:8054=8.8.4.4:53 \
    ;;                          -tcptun :8053=8.8.8.8:53,:8054=8.8.4.4:53
    ;;   	   'undecided-dos)))
    (start-process "ShadowSocks" "*ShadowSocks Server*" "sudo" "systemctl" "start" "shadowsocks-libev@kvm")))

(defun v2ray ()
  (interactive)
  (if (string-equal system-type "windows-nt")
      (progn
      	(unless (process-status "V2Ray")
      	  (set-process-coding-system
      	   (start-process
      	    "V2Ray"
      	    "*V2Ray*"
      	    "Y:/v2ray-windows-64/v2ray.exe")
      	   'undecided-dos)))))

;; (ignore-errors (ss))

(defun frp ()
  (interactive)
  (if (string-equal system-type "windows-nt")
      (progn
      	(unless (process-status "frpc")
      	  (set-process-coding-system
      	   (start-process
      	    "frpc"
      	    "*Frpc*"
      	    "Y:/frp/frpc.exe"
      	    "-c" "Y:/frp/frpc.ini")
      	   'undecided-dos))
	(unless (process-status "mstsc")
      	  (set-process-coding-system
      	   (start-process
      	    "mstsc"
      	    "*Mstsc*"
      	    "mstsc")
	   'undecided-dos)))))

(defun my-sumatra-remove-unused-config ()
  (interactive)
  (while (re-search-forward "^.*FilePath = \\(.*\\.pdf\\)$" nil t)
    (let ((filename
	   (replace-regexp-in-string "\\\\"
				     "/" (match-string 1) t t)))
      (unless (file-exists-p filename)
	(previous-logical-line)
	(eval-and-compile
	  (when (version< emacs-version "25.0")
	    (defalias 'thing-at-point--beginning-of-sexp 'beginning-of-sexp)))
	(thing-at-point--beginning-of-sexp)
	(kill-sexp)
	(delete-blank-lines)))))

(defun my-commit ()
  (interactive)
  (let ((git-command
	 '("cd ~/; git add . && git commit -am \"Update.\" && git push"
	   "cd ~/.emacs.d/; git add . && git commit -am \"Update.\" && git push"
	   "cd ~/repo/hexo-blog/source/; git add . && git commit -am \"Update.\" && git push")))
    (dolist (cmd git-command)
      (call-process-shell-command
       (if (string-equal system-type "windows-nt")
	   (concat "bash -c "
		   (shell-quote-argument cmd))
	 (shell-quote-argument cmd))
       nil 0))))

(defun my-hexo-deploy ()
  "Deploy my hexo site."
  (interactive)
  (let ((c "(cd ~/repo/hexo-blog/ && time (hexo g) &>> /tmp/hexo.log && time (gulp) &>> /tmp/hexo.log && time (hexo d) &>> /tmp/hexo.log || time (hexo d) &>> /tmp/hexo.log)"))
    (async-shell-command
     (if (string-equal system-type "windows-nt")
	 (concat "bash -c "
		 (shell-quote-argument c))
       (shell-quote-argument c)))))

(defun my-flushdns ()
  "Flush DNS."
  (interactive)
  (when (string-equal system-type "windows-nt")
    (async-shell-command "ipconfig -flushdns")))

(defun my-lcdoff ()
  (interactive)
  (when (string-equal system-type "gnu/linux")
    (call-process-shell-command "sleep 1; xset dpms force off" nil 0)))

(defun my-keyrate (&optional disable)
  (interactive (list current-prefix-arg))
  (when (string-equal system-type "windows-nt")
    (if disable
	(call-process-shell-command "/f/diy/keyrate" nil 0)
      (call-process-shell-command "/f/diy/keyrate 200 15" nil 0))))

(defun my-shutdown ()
  (interactive)
  (when (string-equal system-type "windows-nt")
    (call-process-shell-command "shutdown -h" nil 0)))

(defun md-to-clipboard (&optional start end)
  "Copy markdown to formatted text."
  (interactive (if (use-region-p)
		   (list (region-beginning) (region-end))
		 (list (point-min) (point-max))))
  (when (string-equal system-type "windows-nt")
    (let ((output-docx (concat (temporary-file-directory) "tmp.docx"))
	  (data-dir (temporary-file-directory))
	  (reference-docx (concat (temporary-file-directory) "times.docx"))
	  (shell-file-name "/bin/bash"))
      (unless (file-exists-p reference-docx)
	(copy-file "~/.emacs.d/.data/times.docx" data-dir nil))
      (shell-command-on-region
       start end
       (concat "pandoc -f markdown -o "
	       output-docx
	       " --data-dir="
	       data-dir
	       " --reference-doc="
	       reference-docx))
      (w32-shell-execute "open" "~/.emacs.d/.bin/md-docx-clipboard.js"))))

(when (boundp 'ctl-z-map)
  (global-set-key (kbd "C-z w") #'md-to-clipboard)
  (global-set-key (kbd "C-z M-w") #'md-to-clipboard))

(defun my-typographical-quotation-mark (&optional start end)
  "Change straight quotes to curly quotes."
  (interactive (if (use-region-p)
		   (list (region-beginning) (region-end))
		 (list (point) (point-max))))
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (while
	  (or (while (re-search-forward
		      (format
		       "\"\\([^\"]\\{1,%d\\}\\)\""
		       (1+ (- (line-end-position) (line-beginning-position))))
		      nil t)
		(replace-match "“\\1”"))
	      (< (point) (point-max)))
	(forward-line)
	(beginning-of-line)))))

(fset 'my-delete-parentheses (kbd "C-M-% ( \\ ( . + ? \\ ) RET \\ 1 RET !"))
(fset 'my-change-parentheses (kbd "C-M-% （ \\ ( . + ? \\ ) RET ( \\ 1 RET !"))
;; (replace-regexp "（\\(.*\\)）" "(\\1)")

;; (let ((default-directory "/sshx:root@128.199.209.34:/root/"))
;;   (shell (generate-new-buffer-name "*dply*")))

(defun ding-ding-ding ()
  "Ding whatever the settings are."
  (interactive)
  (eval-when-compile
    (require 'cl-macs))
  (let ((ring-bell-function nil)
	(visible-bell nil))
    (cl-loop repeat 100 do (ding) (other-frame 0) (sit-for 1))))

(defun my-pomodoro ()
  "Ding after a pomodoro time"
  (interactive)
  (run-at-time "25 min" nil #'ding-ding-ding))

(defun zmx ()
  (interactive)
  (eval-when-compile
    (require 'zone-matrix))
  (when (fboundp 'zone-matrix)
    (setq zone-programs [zone-matrix])
    (setq zmx-unicode-mode nil)
    (zone)))
